package org.charles.zhifou.controller;

import cn.hutool.core.io.FileUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.charles.zhifou.common.config.AliyunOssConfig;
import org.charles.zhifou.common.exception.BusinessException;
import org.charles.zhifou.common.response.BaseResponse;
import org.charles.zhifou.common.response.ResponseCodeEnum;
import org.charles.zhifou.common.response.ResponseUtils;
import org.charles.zhifou.constant.FileConstant;
import org.charles.zhifou.enums.FileUploadTypeEnum;
import org.charles.zhifou.manager.AliyunOssManager;
import org.charles.zhifou.model.entity.User;
import org.charles.zhifou.service.UserService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.Arrays;

/**
 * <h1>文件上传</h1>
 *
 * @author charles
 * @version 1.0
 */
@RestController
@RequestMapping("/file")
@Slf4j
@Tag(name = "文件上传接口")
public class FileController {

    @Resource
    private AliyunOssConfig ossConfig;

    @Resource
    private AliyunOssManager ossManager;

    @Resource
    private UserService userService;

    @PostMapping("/upload")
    @Operation(summary = "文件上传")
    public BaseResponse<String> uploadFile(
            @RequestPart("file")
                MultipartFile multipartFile,
            @NotNull(message = "文件上传类型不能为空")
                FileUploadTypeEnum fileUploadType
    )
    {
        if (fileUploadType == null) {
            return new BaseResponse<>(ResponseCodeEnum.PARAMS_ERROR, "文件上传类型为空!!");
        }

        validFile(multipartFile, fileUploadType);

        User loginUser = userService.getLoginUser();

        // 访问地址: https://桶名.endpoint名/文件路径
        String uuid = RandomStringUtils.randomAlphanumeric(8);
        String filename = uuid + "-" + multipartFile.getOriginalFilename();
        String filepath = String.format("%s/%s/%s", fileUploadType.getBucketDir(), loginUser.getId(), filename);
        File file = null;
        try {
            // 上传文件
            file = File.createTempFile(filepath, null);
            multipartFile.transferTo(file);
            ossManager.putObject(filepath, file);

            // 返回可访问地址
            String address = String.format("https://%s.%s/%s", ossConfig.getBucketName(), ossConfig.getEndpoint(), filepath);
            return ResponseUtils.success(address);
        } catch (Exception e) {
            log.error("file upload error, filepath = {}", filepath, e);
            throw new BusinessException(ResponseCodeEnum.SYSTEM_ERROR, "上传失败");
        } finally {
            if (file != null) {
                // 删除临时文件
                boolean delete = file.delete();
                if (!delete) {
                    log.error("file delete error, filepath = {}", filepath);
                }
            }
        }
    }

    /**
     * 校验文件
     *
     * @param multipartFile
     * @param fileUploadType 文件上传类型
     */
    private void validFile(MultipartFile multipartFile, FileUploadTypeEnum fileUploadType) {
        // 文件大小
        long fileSize = multipartFile.getSize();

        // 文件后缀
        String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        if (FileUploadTypeEnum.USER_AVATAR.equals(fileUploadType)) {

            if (fileSize > FileConstant.MAX_USER_AVATAR_SIZE_IN_BYTES) {
                throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "头像大小不能超过 " + FileConstant.MAX_USER_AVATAR_SIZE_IN_MB + " MB");
            }

            if (!Arrays.asList("jpeg", "jpg", "svg", "png", "webp").contains(fileSuffix)) {
                throw new BusinessException(ResponseCodeEnum.PARAMS_ERROR, "文件类型错误, 头像必须是图片类型");
            }
        }
    }
}
